class cacheNode {
  key = ''
  value = ''
  prev = null
  next = null

  constructor(k:any, v: any) {
    if (this.valid(k)) this.key = k
    if (this.valid(v)) this.value = v
  }

  valid(key: any) {
    return typeof key != 'undefined' && key !== null
  }
}

class LruCache {
  protected limit = 0
  private head: any = null
  private tail: any = null
  protected map = {}
  private size = 0
  protected cacheTime = 0

  constructor(limit = 30) {
    this.limit = limit
    // head 指针指向表头元素，最常用的元素 | tail为尾部元素，最不常用
    this.head = this.tail = null
    this.map = {}
    this.size = 0
    this.cacheTime = 2 * 60 * 60 * 1000
  }

  getData(url:string, params: any) {
    const key = this.getUrlKey(url, params)
    if (key) {
      const cacheData = this.get(key)
      if (cacheData) {
        if (Date.now() - cacheData.cacheTime >= this.cacheTime) {
          return false
        } else {
          return cacheData.resData
        }
      } else {
        return false
      }
    }
    return false
  }

  setData(url:string, params:any, resData:any) {
    const key = this.getUrlKey(url, params)
    if (key) {
      this.set(key, {
        resData: resData,
        cacheTime: Date.now()
      })
    }
  }

  getUrlKey(url:string, params:any) {
    if (JSON.stringify(params) === '{}') {
      return url
    }
    // 遍历params
    let paramsUrl = '?'
    for (const key in params) {
      if (paramsUrl.length === 1) {
        paramsUrl = paramsUrl + key + '=' + (params[key] ? params[key] : '')
      } else {
        paramsUrl = paramsUrl + '&' + key + '=' + (params[key] ? params[key] : '')
      }
    }
    return url + paramsUrl
  }

  setHead(node: cacheNode) {
    node.next = this.head
    node.prev = null
    if (this.head !== null) {
      this.head.prev = node
    }
    if (this.tail === null) this.tail = node
    this.size++
    this.map[node.key] = node
  }

  set(key:string, value:any) {
    const node = new cacheNode(key, value)
    if (this.map[key]) {
      this.map[key].value = node.value
      this.remove(node.key)
    } else {
      if (this.size >= this.limit) {
        delete this.map[this.tail['key']]
        this.size--
        this.tail = this.tail && this.tail['prev']
        this.tail['next'] = null
      }
    }
    this.setHead(node)
  }

  get(key:string) {
    if (this.map[key]) {
      const value = this.map[key].value
      const node = new cacheNode(key, value)
      this.remove(key)
      this.setHead(node)
      return value
    } else {
      return false
    }
  }

  remove(key:string) {
    const node = this.map[key]
    if (node.prev !== null) {
      node.prev.next = node.next
    } else {
      this.head = node.next
    }
    if (node.next !== null) {
      node.next.prev = node.prev
    } else {
      this.tail = node.prev
    }
    delete this.map[key]
    this.size--
  }
}

module.exports = LruCache
